/* eslint-disable @typescript-eslint/no-explicit-any */
declare namespace CM_Types {
  namespace Xhr {
    interface Details {
      binary?: boolean;
      headers?: Record<string, string>;
      method?: "GET" | "POST" | "HEAD";
      overrideMimeType?: Parameters<
        typeof XMLHttpRequest.prototype.overrideMimeType
      >[0];
      password?: string;
      timeout?: typeof XMLHttpRequest.prototype.timeout;
      user?: string;
    }
    interface Progress extends Response {
      readonly lengthComputable?: typeof ProgressEvent.prototype.lengthComputable;
      readonly loaded?: typeof ProgressEvent.prototype.loaded;
      readonly total?: typeof ProgressEvent.prototype.total;
    }
    interface Response {
      readonly finalUrl?: string;
      readonly readyState?:
        | typeof XMLHttpRequest.UNSENT
        | typeof XMLHttpRequest.OPENED
        | typeof XMLHttpRequest.HEADERS_RECEIVED
        | typeof XMLHttpRequest.LOADING
        | typeof XMLHttpRequest.DONE;
      readonly response?: typeof XMLHttpRequest.prototype.response;
      readonly responseHeaders?: ReturnType<
        typeof XMLHttpRequest.prototype.getAllResponseHeaders
      >;
      readonly responseText?: typeof XMLHttpRequest.prototype.responseText;
      readonly responseXML?:
        | typeof XMLHttpRequest.prototype.responseXML
        | false;
      readonly status?: typeof XMLHttpRequest.prototype.status;
      readonly statusText?: typeof XMLHttpRequest.prototype.statusText;
    }
    interface Return {
      abort: typeof XMLHttpRequest.prototype.abort;
    }
  }
  namespace Notification {
    interface Option {
      text: browser.notifications.NotificationOptions["message"];
      title?: browser.notifications.NotificationOptions["title"];
      image?: browser.notifications.NotificationOptions["iconUrl"];
    }
  }
}

type Promisize<T extends (...args: any[]) => any> = T extends (
  ...args: infer P
) => infer R
  ? (...args: P) => Promise<R>
  : never;

type PromisizeReturn<T extends (...args: any[]) => any, R> = T extends (
  ...args: infer P
) => unknown
  ? (...args: P) => Promise<R>
  : never;

type AnyRecord = Record<string | number, unknown>;

type CM_getValue = (key: string, defaultValue?: unknown) => unknown;
type CM_setValue = (key: string, value: unknown) => void;
type CM_listValues = () => string[];
type CM_deleteValue = (key: string) => void;

type CM_getTab = (callback: (tab: AnyRecord) => void) => void;
type CM_saveTab = (tab: AnyRecord) => void;
type CM_getTabs = (callback: (tab: Record<number, AnyRecord>) => void) => void;

interface CM_Object {
  getValue: Promisize<CM_getValue>;
  setValue: Promisize<CM_setValue>;
  listValues: Promisize<CM_listValues>;
  deleteValue: Promisize<CM_deleteValue>;
}

type unsafeWindow = typeof window & AnyRecord;
